#include "libcomm.h"
#ifdef COMM_MSVC

////////////////////////////////////////////////////////////////////////// NTServiceManager

class NTServiceManager
{
public:
	static bool IsInstalled(const char* name)
	{
		MYLIB_ASSERT_NOTNULL(name);
		bool result = false;
		SC_HANDLE scmanager = NULL;
		SC_HANDLE service = NULL;
		do 
		{
			scmanager = ::OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
			if(NULL == scmanager)
			{
				LOGFUNCERROR(OpenSCManager);
				break;
			}

			service = ::OpenServiceA(scmanager, name, SERVICE_QUERY_STATUS);
			if(NULL == service)
			{
				if(ERROR_SERVICE_DOES_NOT_EXIST != GetLastError())
					LOGFUNCERROR(OpenService);
				break;
			}

			result = true;

		} while (false);

		if(NULL != service)
		{
			::CloseServiceHandle(service);
			service = NULL;
		}

		if(NULL != scmanager)
		{
			::CloseServiceHandle(scmanager);
			scmanager = NULL;
		}

		return result;
	}

	static bool Install(const char* name, const char* displayName, NTService::ServiceStartupType type)
	{
		MYLIB_ASSERT(NULL != name && NULL != displayName);
		bool result = false;
		SC_HANDLE scmanager = NULL;
		SC_HANDLE service = NULL;
		do 
		{
			scmanager = ::OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT|SC_MANAGER_CREATE_SERVICE);
			if(NULL == scmanager)
			{
				LOGFUNCERROR(OpenSCManager);
				break;
			}

			char filePath[MAX_PATH] = {0};
			::GetModuleFileNameA(NULL, filePath, MAX_PATH);
			int startupType = GetRealStartupType(type);
			service = CreateServiceA( 
				scmanager,												// SCM database 
				name,                                                   // name of service 
				displayName,											// service name to display 
				SERVICE_ALL_ACCESS,										// desired access 
				SERVICE_WIN32_OWN_PROCESS|SERVICE_INTERACTIVE_PROCESS,  // service type 
				startupType,											// start type 
				SERVICE_ERROR_NORMAL,									// error control type 
				filePath,												// path to service's binary 
				NULL,                                                   // no load ordering group 
				NULL,                                                   // no tag identifier 
				NULL,                                                   // no dependencies 
				NULL,                                                   // LocalSystem account 
				NULL);													// no password
			if(NULL == service)
			{
				LOGFUNCERROR(OpenServiceA);
				break;
			}

			result = true;

		} while (false);

		if(NULL != service)
		{
			::CloseServiceHandle(service);
			service = NULL;
		}

		if(NULL != scmanager)
		{
			::CloseServiceHandle(scmanager);
			scmanager = NULL;
		}

		return result;
	}

	static bool UnInstall(const char* name)
	{
		MYLIB_ASSERT_NOTNULL(name);
		bool result = false;
		SC_HANDLE scmanager = NULL;
		SC_HANDLE service = NULL;
		SERVICE_STATUS status = {0};
		do 
		{
			scmanager = ::OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
			if(NULL == scmanager)
			{
				LOGFUNCERROR(OpenSCManager);
				break;
			}

			service = ::OpenServiceA(scmanager, name, SERVICE_STOP|SERVICE_QUERY_STATUS|DELETE);
			if(NULL == service)
			{
				LOGFUNCERROR(OpenServiceA);
				break;
			}

			if (!QueryServiceStatus(service, &status))
			{
				LOGFUNCERROR(QueryServiceStatus);
				break;
			}
			if(status.dwCurrentState != SERVICE_STOPPED)
			{
				// waiting for service to stop if in stopping state...
				if(!WaitingIfPending(service,status,SERVICE_STOP_PENDING))
					break;

				if (!::ControlService(service, SERVICE_CONTROL_STOP, &status))
				{
					LOGFUNCERROR(ControlService);
					break;
				}

				// waiting for service to stop synchronously...
				if(!WaitingIfPending(service,status,SERVICE_STOP_PENDING))
					break;
			}

			if(!::DeleteService(service))
			{
				LOGFUNCERROR(DeleteService);
				break;
			}

			result = true;

		} while (false);

		if(NULL != service)
		{
			::CloseServiceHandle(service);
			service = NULL;
		}

		if(NULL != scmanager)
		{
			::CloseServiceHandle(scmanager);
			scmanager = NULL;
		}

		return result;
	}

	static bool SetStartupType(const char* name, NTService::ServiceStartupType type)
	{
		MYLIB_ASSERT_NOTNULL(name);
		bool result = false;
		SC_HANDLE scmanager = NULL;
		SC_HANDLE service = NULL;
		do 
		{
			scmanager = ::OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
			if(NULL == scmanager)
			{
				LOGFUNCERROR(OpenSCManager);
				break;
			}

			service = ::OpenServiceA(scmanager, name, SERVICE_CHANGE_CONFIG);
			if(NULL == service)
			{
				LOGFUNCERROR(OpenServiceA);
				break;
			}

			int startupType = GetRealStartupType(type);
			if(!ChangeServiceConfig( 
				service,                                        // handle of service 
				SERVICE_NO_CHANGE,								// service type: no change 
				startupType,									// service start type 
				SERVICE_NO_CHANGE,								// error control: no change 
				NULL,											// binary path: no change 
				NULL,											// load order group: no change 
				NULL,											// tag ID: no change 
				NULL,											// dependencies: no change 
				NULL,											// account name: no change 
				NULL,											// password: no change 
				NULL))											// display name: no change
			{
				LOGFUNCERROR(ChangeServiceConfig);
				break;
			}
			
			result = true;

		} while (false);

		if(NULL != service)
		{
			::CloseServiceHandle(service);
			service = NULL;
		}

		if(NULL != scmanager)
		{
			::CloseServiceHandle(scmanager);
			scmanager = NULL;
		}

		return result;
	}

	static bool UpdateDesc(const char* name, const char* desc)
	{
		MYLIB_ASSERT(NULL != name && NULL != desc);
		bool result = false;
		SC_HANDLE scmanager = NULL;
		SC_HANDLE service = NULL;
		do 
		{
			scmanager = ::OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
			if(NULL == scmanager)
			{
				LOGFUNCERROR(OpenSCManager);
				break;
			}

			service = ::OpenServiceA(scmanager, name, SERVICE_CHANGE_CONFIG);
			if(NULL == service)
			{
				LOGFUNCERROR(OpenServiceA);
				break;
			}

			SERVICE_DESCRIPTIONA sd = {0};
			sd.lpDescription = (char*)desc;
			if(!ChangeServiceConfig2A(service, SERVICE_CONFIG_DESCRIPTION, &sd))
			{
				LOGFUNCERROR(ChangeServiceConfig2);
				break;
			}

			result = true;

		} while (false);

		if(NULL != service)
		{
			::CloseServiceHandle(service);
			service = NULL;
		}

		if(NULL != scmanager)
		{
			::CloseServiceHandle(scmanager);
			scmanager = NULL;
		}

		return result;
	}

	static bool Start(const char* name, int argc, const char** argv)
	{
		MYLIB_ASSERT(NULL != name);
		bool result = false;
		SC_HANDLE scmanager = NULL;
		SC_HANDLE service = NULL;
		SERVICE_STATUS status = {0};
		do 
		{
			scmanager = ::OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
			if(NULL == scmanager)
			{
				LOGFUNCERROR(OpenSCManager);
				break;
			}

			service = ::OpenServiceA(scmanager, name, SERVICE_ALL_ACCESS);
			if(NULL == service)
			{
				LOGFUNCERROR(OpenServiceA);
				break;
			}

			if (!QueryServiceStatus(service, &status))
			{
				LOGFUNCERROR(QueryServiceStatus);
				break;
			}
			if(status.dwCurrentState != SERVICE_STOPPED 
				&& status.dwCurrentState != SERVICE_STOP_PENDING)
			{
				LOGWARN("%s: NT-Service \"%s\" is in running state already.",__FUNCTION__,name);
				break;
			}

			// waiting for service to stop if in stopping state...
			if(!WaitingIfPending(service,status,SERVICE_STOP_PENDING))
				break;

			if (!::StartServiceA(service, argc, argv))
			{
				LOGFUNCERROR(StartServiceA);
				break;
			}

			if (!QueryServiceStatus(service, &status))
			{
				LOGFUNCERROR(QueryServiceStatus);
				break;
			}

			// waiting for service to start synchronously...
			if(!WaitingIfPending(service,status,SERVICE_START_PENDING))
				break;

			result = true;

		} while (false);

		if(NULL != service)
		{
			::CloseServiceHandle(service);
			service = NULL;
		}

		if(NULL != scmanager)
		{
			::CloseServiceHandle(scmanager);
			scmanager = NULL;
		}

		return result;
	}

	static bool Stop(const char* name)
	{
		MYLIB_ASSERT_NOTNULL(name);
		bool result = false;
		SC_HANDLE scmanager = NULL;
		SC_HANDLE service = NULL;
		SERVICE_STATUS status = {0};
		do 
		{
			scmanager = ::OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
			if(NULL == scmanager)
			{
				LOGFUNCERROR(OpenSCManager);
				break;
			}

			service = ::OpenServiceA(scmanager, name, SERVICE_STOP|SERVICE_QUERY_STATUS);
			if(NULL == service)
			{
				LOGFUNCERROR(OpenServiceA);
				break;
			}

			if (!QueryServiceStatus(service, &status))
			{
				LOGFUNCERROR(QueryServiceStatus);
				break;
			}
			if(status.dwCurrentState == SERVICE_STOPPED)
			{
				LOGWARN("%s: NT-Service \"%s\" is in stop state already.",__FUNCTION__,name);
				break;
			}

			// waiting for service to stop if in stopping state...
			if(!WaitingIfPending(service,status,SERVICE_STOP_PENDING))
				break;

			if (!::ControlService(service, SERVICE_CONTROL_STOP, &status))
			{
				LOGFUNCERROR(ControlService);
				break;
			}

			// waiting for service to stop synchronously...
			if(!WaitingIfPending(service,status,SERVICE_STOP_PENDING))
				break;
			
			result = true;

		} while (false);

		if(NULL != service)
		{
			::CloseServiceHandle(service);
			service = NULL;
		}

		if(NULL != scmanager)
		{
			::CloseServiceHandle(scmanager);
			scmanager = NULL;
		}

		return result;
	}

	static bool GetCurrentStatus(const char* name, DWORD& dwCurrentState)
	{
		MYLIB_ASSERT(NULL != name);
		bool result = false;
		SC_HANDLE scmanager = NULL;
		SC_HANDLE service = NULL;
		SERVICE_STATUS status = {0};
		do 
		{
			scmanager = ::OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
			if(NULL == scmanager)
			{
				LOGFUNCERROR(OpenSCManager);
				break;
			}

			service = ::OpenServiceA(scmanager, name, SERVICE_QUERY_STATUS);
			if(NULL == service)
			{
				LOGFUNCERROR(OpenServiceA);
				break;
			}

			if (!QueryServiceStatus(service, &status))
			{
				LOGFUNCERROR(QueryServiceStatus);
				break;
			}

			dwCurrentState = status.dwCurrentState;
			result = true;

		} while (false);

		if(NULL != service)
		{
			::CloseServiceHandle(service);
			service = NULL;
		}

		if(NULL != scmanager)
		{
			::CloseServiceHandle(scmanager);
			scmanager = NULL;
		}

		return result;
	}

private:
	static int GetRealStartupType(NTService::ServiceStartupType type)
	{
		switch (type)
		{
		case NTService::SST_AUTO_START:
			{
				return SERVICE_AUTO_START;
			}
		case NTService::SST_MANUAL_START:
			{
				return SERVICE_DEMAND_START;
			}
		case NTService::SST_DISABLED:
		default:
			break;
		}
		return SERVICE_DISABLED;
	}

	static bool WaitingIfPending(SC_HANDLE service, SERVICE_STATUS& status, DWORD pending)
	{
		MYLIB_ASSERT(SERVICE_START_PENDING==pending||SERVICE_STOP_PENDING==pending);
		Timer timer;
		timer.Start();
		DWORD dwOldCheckPoint = status.dwCheckPoint;

		while (status.dwCurrentState == pending)
		{
			::Sleep(status.dwWaitHint / 10);

			if (!QueryServiceStatus(service, &status))
			{
				LOGFUNCERROR(QueryServiceStatus);
				break;
			}

			if (status.dwCheckPoint > dwOldCheckPoint)
			{
				timer.Start();
				dwOldCheckPoint = status.dwCheckPoint;
			}
			else
			{
				if (timer.Elapse() / 1000 > status.dwWaitHint)
				{
					LOGWARN("waiting timeout(%dms) for NT-Service to %s.",status.dwWaitHint,
						(SERVICE_START_PENDING==pending)?"start":"stop");
					break;
				}
			}
		}

		return (status.dwCurrentState!=pending);
	}
};


////////////////////////////////////////////////////////////////////////// NTServiceInstance

class NTServiceInstance
{
public:
	NTServiceInstance(ServiceTask* service, const char* name, bool canStop, bool canShutdown, bool canPausecontinue, int waitTimeoutMs=1000)
		:m_service(service),m_name(name)
	{
		MYLIB_ASSERT_NOTNULL(m_service);
		m_this = this;
		memset(&m_status, 0, sizeof(SERVICE_STATUS));
		m_status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
		m_status.dwCurrentState = SERVICE_START_PENDING;
		m_status.dwWin32ExitCode = NO_ERROR;
		m_status.dwServiceSpecificExitCode = 0;
		m_status.dwCheckPoint = 0;
		m_status.dwWaitHint = waitTimeoutMs;

		if (canStop)
			m_status.dwControlsAccepted |= SERVICE_ACCEPT_STOP;
		if (canShutdown)
			m_status.dwControlsAccepted |= SERVICE_ACCEPT_SHUTDOWN;
		if (canPausecontinue)
			m_status.dwControlsAccepted |= SERVICE_ACCEPT_PAUSE_CONTINUE;

		m_status_handle = NULL;
	}

	bool Run()
	{
		SERVICE_TABLE_ENTRYA st[] =
		{
			{(LPSTR)m_name, (LPSERVICE_MAIN_FUNCTIONA)ServiceMainHandler},
			{NULL, NULL}
		};

		if(!::StartServiceCtrlDispatcherA(st))
		{
			LOGFUNCERROR(StartServiceCtrlDispatcher);
			return false;
		}
		return true;
	}

private:
	static void ServiceMainHandler(DWORD argc, LPSTR *argv)
	{
		m_this->m_status_handle = RegisterServiceCtrlHandlerA(m_this->m_name, (LPHANDLER_FUNCTION)ServiceCtrlHandler);
		if(NULL == m_this->m_status_handle)
		{
			LOGFUNCERROR(StartServiceCtrlDispatcher);
			return;
		}
		m_this->Start(argc, argv);
	}

	static void ServiceCtrlHandler(DWORD ctrl)
	{
		switch (ctrl)
		{ 
		case SERVICE_CONTROL_STOP:
			{
				m_this->Stop();
			}
			break;
		case SERVICE_CONTROL_PAUSE:
			{
				m_this->Pause();
			}
			break;
		case SERVICE_CONTROL_CONTINUE:
			{
				m_this->Continue();
			}
			break;
		case SERVICE_CONTROL_SHUTDOWN:
			{
				m_this->Shutdown();
			}
			break;
		case SERVICE_CONTROL_INTERROGATE:
		default:
			break;
		}
	}

	void Start(DWORD argc, LPSTR *argv)
	{
		try
		{
			SetServiceStatus(SERVICE_START_PENDING);
			if (m_service->OnInit(argc, argv))
			{
				SetServiceStatus(SERVICE_RUNNING);
				m_service->OnStart();
			}
			SetServiceStatus(SERVICE_STOPPED);
		}
		catch (DWORD dwError)
		{
			SetServiceStatus(SERVICE_STOPPED, dwError);
		}
		catch (...)
		{
			SetServiceStatus(SERVICE_STOPPED);
		}
	}

	void Stop()
	{
		DWORD dwOriginalState = m_status.dwCurrentState;
		try
		{
			SetServiceStatus(SERVICE_STOP_PENDING);
			m_service->OnStop();
			SetServiceStatus(SERVICE_STOPPED);
		}
		catch (DWORD dwError)
		{
			dwError = 0;
			SetServiceStatus(dwOriginalState);
		}
		catch (...)
		{
			SetServiceStatus(dwOriginalState);
		}
	}

	void Pause()
	{
		try
		{
			SetServiceStatus(SERVICE_PAUSE_PENDING);
			m_service->OnPause();
			SetServiceStatus(SERVICE_PAUSED);
		}
		catch (DWORD dwError)
		{
			dwError = 0;
			SetServiceStatus(SERVICE_RUNNING);
		}
		catch (...)
		{
			SetServiceStatus(SERVICE_RUNNING);
		}
	}

	void Continue()
	{
		try
		{
			SetServiceStatus(SERVICE_CONTINUE_PENDING);
			m_service->OnContinue();
			SetServiceStatus(SERVICE_RUNNING);
		}
		catch (DWORD dwError)
		{
			dwError = 0;
			SetServiceStatus(SERVICE_PAUSED);
		}
		catch (...)
		{
			SetServiceStatus(SERVICE_PAUSED);
		}
	}

	void Shutdown()
	{
		try
		{
			m_service->OnShutdown();
			SetServiceStatus(SERVICE_STOPPED);
		}
		catch (DWORD dwError)
		{
			dwError = 0;
		}
		catch (...)
		{
		}
	}

	void SetServiceStatus(DWORD dwCurrentState, DWORD dwWin32ExitCode=NO_ERROR)
	{
		MYLIB_ASSERT_NOTNULL(m_status_handle);

		static DWORD dwCheckPoint = 0;
		m_status.dwCurrentState = dwCurrentState;
		m_status.dwWin32ExitCode = dwWin32ExitCode;

		if (dwCurrentState==SERVICE_RUNNING
			|| dwCurrentState==SERVICE_STOPPED)
		{
			m_status.dwCheckPoint = 0;
		}
		else 
		{
			m_status.dwCheckPoint = ++dwCheckPoint;
		}

		::SetServiceStatus(m_status_handle, &m_status);
	}

private:
	ServiceTask* m_service;
	String m_name;
	SERVICE_STATUS m_status;
	SERVICE_STATUS_HANDLE m_status_handle;
	static NTServiceInstance* m_this;
};
NTServiceInstance* NTServiceInstance::m_this = NULL;


////////////////////////////////////////////////////////////////////////// NTService

NTService::NTService(const char* name):m_name(name){}
NTService::~NTService(){}
bool NTService::IsInstalled(){ return NTServiceManager::IsInstalled(m_name); }
bool NTService::Install(const char* displayName, ServiceStartupType type){ return NTServiceManager::Install(m_name,displayName,type); }
bool NTService::UnInstall(){ return NTServiceManager::UnInstall(m_name); }
bool NTService::SetStartupType(ServiceStartupType type){ return NTServiceManager::SetStartupType(m_name,type); }
bool NTService::UpdateDesc(const char* desc){ return NTServiceManager::UpdateDesc(m_name,desc); }
bool NTService::Start(int argc, const char** argv){ return NTServiceManager::Start(m_name,argc,argv); }
bool NTService::Stop(){ return NTServiceManager::Stop(m_name); }
bool NTService::GetCurrentStatus(DWORD& dwCurrentState){ return NTServiceManager::GetCurrentStatus(m_name,dwCurrentState); }
bool NTService::Main(ServiceTask* service,
					bool canStop,
					bool canShutdown,
					bool canPausecontinue,
					int waitTimeoutMs)
{
	NTServiceInstance* serviceInst = new NTServiceInstance(service,m_name,canStop,canShutdown,canPausecontinue,waitTimeoutMs);
	MYLIB_ASSERT_NOTNULL(serviceInst);
	return serviceInst->Run();
}

////////////////////////////////////////////////////////////////////////// CommNTService

class CommServiceTask : public ServiceTask
{
public:
	ThreadSemaphore m_exit_sem;
	String m_runCommandPath;
	bool m_restartWhenCrash;
	bool m_runAsUserSession;
	ScopedPtr<Process> m_process;
	Arguments m_args;
	CommServiceTask(const char* runCommandPath, bool restartWhenCrash, bool runAsUserSession)
		:m_runCommandPath(runCommandPath),m_restartWhenCrash(restartWhenCrash),m_runAsUserSession(runAsUserSession){}

	virtual bool OnInit(int argc, char** argv)
	{
		for(int i=1;i<argc;i++)
		{
			LOGNOTICE("NT-Service-Instance argv[%d]: %s.", i-1,argv[i]);
			m_args << argv[i];
		}
		return true;
	}

	virtual void OnStart()
	{
		LOGNOTICE("NT-Service-Instance is going to start...");
		do 
		{
			int exitcode = 0;
			if(m_runAsUserSession)
				m_process = Process::ExecuteAsUser(m_runCommandPath,m_args,3000,true);
			else
				m_process = Process::Execute(m_runCommandPath,m_args,Arguments(),true);
			if(m_process == NULL)
				break;
			if(!m_process->Join(&exitcode))
				break; 
			if(-1 == exitcode)
			{
				LOGWARN("NT-Service-Instance is terminated.");
				break;// terminate process in OnStop().
			}
			// crash.
			LOGWARN("NT-Service-Instance unexpected crash!");
			if(!m_restartWhenCrash)
				break;
			Thread::Sleep(3000);
			LOGWARN("NT-Service-Instance is going to restart...");

		} while (TRUE);
		LOGDEBUG("NT-Service is stopped.");
		m_exit_sem.SetSignal();
	}

	virtual void OnStop()
	{
		LOGNOTICE("NT-Service-Instance is going to stop...");
		if(m_process != NULL)
		{
			m_process->Terminate();
			m_exit_sem.WaitSignal(5000);
		}
	}

	virtual void OnShutdown()
	{
		LOGNOTICE("NT-Service-Instance is going to shutdown...");
		OnStop();
	}
};

CommNTService::CommNTService(const char* serviceName, const char* serviceDisplay, const char* serviceDescription, NTService::ServiceStartupType serviceType, 
							 const char* runCommand, bool restartWhenCrash,bool runAsUserSession):m_service(serviceName),
							 m_serviceName(serviceName),m_serviceDisplay(serviceDisplay),m_serviceDescription(serviceDescription),m_serviceType(serviceType),
							 m_runCommandPath(runCommand),m_restartWhenCrash(restartWhenCrash),m_runAsUserSession(runAsUserSession)
{
}

int CommNTService::Main(int argc, char* argv[])
{
	if(argc > 1)
	{
		if(strcmp(argv[1],"-i") == 0)
		{
			if(m_service.IsInstalled() && !m_service.UnInstall())
			{
				LOGWARN("Install NT-Service failure: Uninstall existing NT-Service failure.");
				return -1;
			}
			if(!m_service.Install(m_serviceDisplay,m_serviceType))
			{
				LOGWARN("Install NT-Service failure.");
				return -1;
			}
			if(!m_service.UpdateDesc(m_serviceDescription))
			{
				LOGWARN("Update NT-Service description failure.");
			}
			LOGINFO("Install NT-Service success!");
		}
		else if(strcmp(argv[1],"-u") == 0)
		{
			if(m_service.IsInstalled() && !m_service.UnInstall())
			{
				LOGWARN("Uninstall NT-Service failure.");
				return -1;
			}
			LOGINFO("Uninstall NT-Service success!");
		}
		else if(strcmp(argv[1],"-r") == 0)
		{
			if(!m_service.Start())
			{
				LOGWARN("Start NT-Service failure.");
				return -1;
			}
			LOGINFO("Start NT-Service success!");
		}
		else if(strcmp(argv[1],"-s") == 0)
		{
			if(!m_service.Stop())
			{
				LOGWARN("Stop NT-Service failure.");
				return -1;
			}
			LOGINFO("Stop NT-Service success!");
		}
		else if(strcmp(argv[1],"-t") == 0)
		{
			DWORD dwCurrentState = -1;
			if(!m_service.GetCurrentStatus(dwCurrentState))
				LOGWARN("Query NT-Service status failure.");
			else
				LOGWARN("Query NT-Service status success: %d.",dwCurrentState);
			return dwCurrentState;
		}
		else if(strcmp(argv[1],"-d") == 0)
		{
			// debug mode.
			//
			CommServiceTask instance(m_runCommandPath,m_restartWhenCrash,m_runAsUserSession);
			instance.OnInit(argc,argv);
			instance.OnStart();
		}

		return 0;
	}

	CommServiceTask task(m_runCommandPath,m_restartWhenCrash,m_runAsUserSession);
	return m_service.Main(&task);
}

#endif
